;its main task is to load loader to 630kb:0x9d800  

%define _BOOT_MAC_EXTERN_OR_GLOBAL_ 1 
%define _BOOT_ASM_ 1 

%include"../include/boot.mac" 
%include"../include/parse_elf.mac" 
%include"../include/utils.mac" 

%ifdef _BOOT_ELF_O_ ;boot.o 
[section .text] 
%endif 

%ifndef _BOOT_ELF_O_ 
;start of program 
start: 
	;initialize datasegment 
	;current segment is:0x7c0 
	mov ax,BOOT_SEG  
	mov ds,ax   
	mov es,ax   

	;stack segment 
	mov ax,STACK_SEG 
	mov ss,ax 
	mov sp,STACK_SP  

;display loading string:'Loading boot loader...'  
	call clear_screen_via_bios ;clear screen  

	;int 10h,ah=0x13,show string  
	SHOW_STRING_VIA_BIOS loading_str,loading_str_len 
	call read_loader ;read loader in elf format  

	;parse loader(elf format) 
	CLEAR_REGS_MULTI_XOR ax,esi,edi 

	;get loader segments' total size  
	mov esi,LOADER_ELF_START_ADDR 
	mov edi,loader_seg_total_size  
	mov ax,word[esi+E_PHNUM_FILE_OFF] ;e_phnum 
	push esi 
	push edi 
	push ax 
	call get_seg_size_in_ph 

	;get loader program header table's size 
	mov edi,loader_ph_table_size 
	push esi 
	push edi 
	call get_ph_table_size 

	;copy all segments to LOADER_ELF_START_ADDR 
	mov edi,LOADER_ELF_START_ADDR ;dest  
	add esi,E_HEADER_SIZE 
	add esi,dword[loader_ph_table_size] ;src 
	push edi 
	push esi 
	push dword[loader_seg_total_size] ;bytes 
	call memory_copy 

	JMP_TO_LOADER ;jump to loader  

;read loader into memory address:0x9d80(630kb) 
;loader is reside on sector from number 2 to 21 
;20 sectors for loader 
;input:none 
;output:none 
read_loader: 
	push ax 
	push bx 
	push cx 
	push dx 
	push bp 

	mov ax,LOADER_ELF_SEG  ;segment of loader in elf format  
	mov es,ax 
	mov bx,LOADER_ELF_OFF ;offset,es:bx 

.read:  ;read loader from sector   
	mov ah,READ_LOADER_FUN ;function number:02H 
	mov al,READ_LOADER_COUNT ;read count:17 sectors 
	mov ch,READ_LOADER_TRACK ;track 0 
	mov cl,READ_LOADER_FIRST_SECTOR  ;first sector:02   
	mov dh,READ_LOADER_HEAD ;head 0 
	mov dl,READ_LOADER_DRIVE ;dirve 0  
	
	int 13H ;read 
	jnc .load_ok ;load successful  

;load loader error 	
.load_error: 
	;clear screen 
	call clear_screen_via_bios 

	;show error string 
	SHOW_STRING_VIA_BIOS str_loading_error,str_loading_error_len 

.reset_read:  
	reset_drive  ;reset drive and read again 
	jmp .read ;read again   

;load successfuly 
.load_ok:   
	pop bp 
	pop dx 
	pop cx 
	pop bx 
	pop ax 
	ret 
%endif 

;show string routine via bios routine 
;int 10H,AH=13H
;input: 
;	1.AL.Write mode; 
;	2.BX.BH=Page Number;BL=color;
;	3.CX.String length; 
;	4.DX.DH=Row number;DH=Colum Number. 
;	5.String off.Offset of string. 

;Stack frame: 
;|al	|  
;|bx	| 
;|cx	| 
;|dx	| 
;|off	|(16 bits)  

;|ip	| 
;|bp	| 
show_string_via_bios: 
	push bp 
	mov bp,sp ;stack frame pointer 
	push ax 
	push bx 
	push cx 
	push dx 

	mov ah,0x13 
	mov al,byte[bp+12] 
	mov bx,word[bp+10] 
	mov cx,word[bp+8] 
	mov dx,word[bp+6] 
	mov bp,word[bp+4] 
	int 10H 

	pop dx 
	pop cx 
	pop bx 
	pop ax 
	pop bp 
	ret 9 

;clear screen via bios routine 
;int 10H,AH=06H 
;input:
;	1.AL.AL=lines to scroll(0=clear,CX,DX are used); 
;	2.BX.BH=Background color;BL=Forground color; 
;	3.CX.CH=Upper row number;CL=Left column number;
;	4.DX.DH=Lower row number;DL=Right column number. 

;Stack frame: 
;|al	| 
;|bx	| 
;|cx	| 
;|dx	|

;|ip	| 
;|bp	| 
clear_screen_via_bios: 
	push bp  
	mov bp,sp ;stack frame pointer 
	push ax 
	push bx 
	push cx 
	push dx 

	mov ah,06h 
	mov al,byte[bp+10] 
	mov bx,word[bp+8] 
	mov cx,word[bp+6] 
	mov dx,word[bp+4] 
	int 10h  

	pop dx 
	pop cx 
	pop bx 
	pop ax 
	pop bp 
	ret 7 

;memory copy 
;input:
;	1.destination address; 
;	2.source address;
;	3.bytes bytes to copy.
;output:none

;Stack frame:
;|dest	|(32 bits)  
;|src	|(32 bits)  
;|bytes	|(32 bits)  

;|ip	|
;|bp	| 
memory_copy:
	push bp ;frame pointer 
	mov bp,sp 
	push ax 
	push ecx 
	push esi 
	push edi 
	pushfd 

	mov ecx,dword[bp+2] ;bytes to copy  
	mov esi,dword[bp+6] ;source address 
	mov edi,dword[bp+10] ;destination address  
	cmp ecx,0 
	jle .exit ;bytes <= 0 

;copy bytes 
.bytes_again: 
	mov ax,word[esi]
	mov word[edi],ax 

	inc esi 
	inc edi 
	sub ecx,0  
	cmp ecx,0 
	jle .exit ;bytes <= 0  
	jmp .bytes_again ;copy again  

.exit: 
	popfd 
	pop edi 
	pop esi 
	pop ecx 
	push ax 
	pop bp 
	ret 

;get all segments total size from program header of elf file 
;input: 
;	1.elf addr.Starting address of elf file in memory; 
;	2.size addr.Address of total bytes return. 
;output: 
;	1.total bytes store in dword[size addr] 

;Stack frame:
;|elf addr	|(32 bits)  
;|size addr|(32 bits) 
;|e_phnum	|(16 bits)  

;|ip		|(16 bits)  
;|bp		|(16 bits) 
get_seg_size_in_ph: 
	push bp 
	mov bp,sp ;stack frame 
	push eax 
	push cx 
	push esi 
	push edi 
	pushfd 

	mov cx,word[bp+4] ;e_phnum 
	cmp cx,0 
	jle .exit ;e_phnum <=0  
	mov esi,dword[bp+6] ;bytes addr  
	mov edi,dword[bp+10] ;elf addr 

	add esi,P_FILESZ_FIRST_OFF 
.total_filesz_again: 
	mov eax,dword[esi] 
	add dword[edi],eax 

	add esi,PH_ENTRY_SIZE 
	sub cx,1 
	cmp cx,0 
	jle .exit ;e_phnum <= 0  
	jmp .total_filesz_again 

.exit: 
	popfd 
	pop edi 
	pop esi 
	pop cx 
	pop eax 
	pop bp 
	ret 8 

;get program header table size 
;input:
;	1.elf addr.Starting memory address of elf file;  
;	2.size addr.Address to store program header table size. 
;output:
;	1.dword[size addr].Total bytes store in dword[size_addr].

;Stack frame: 
;|elf addr	|(32 bits)  
;|size addr	|(32 bits)  

;|ip		|(16 bits)  
;|bp		|(16 bits)  
get_ph_table_size: 
	push bp 
	mov bp,sp 
	push cx 
	push esi 
	push edi 
	pushfd 

	mov edi,dword[bp+4] 
	mov esi,dword[bp+8]  
	mov cx,word[esi+E_PHNUM_FILE_OFF] 
	cmp cx,0 
	jle .exit 

.size_total_again: 
	add dword[edi],PH_ENTRY_SIZE  
	sub cx,1 
	cmp cx,0 
	jle .exit  
	jmp .size_total_again 
	
.exit: 
	popfd 
	pop edi 
	pop esi 
	pop cx 
	pop bp 
	ret 8 

%ifdef _BOOT_ELF_O_ ;boot.o 
[section .data] 
%endif 
;some string definitions for loading 
string_def:  
	;loading string 
	loading_str  db 'Loading...' 
	loading_str_len  equ $ - loading_str 

	;loading error 
	str_loading_error db 'Read Error!'  
	str_loading_error_len equ $ - str_loading_error 

	loader_seg_total_size dd 0 ;total file size of loader(elf) segments 
	loader_ph_table_size dd 0 ;program header table size of loader(elf)  

%ifndef _BOOT_ELF_O_ ;boot.o  
fill_rest_space: 
	times 510 - ($ - $$) db 00 ;fill with 00 
	dw 0xAA55 ;signature 
%endif 
